package com.htstar.ovms.report.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.htstar.ovms.admin.api.feign.EtpInfoFeign;
import com.htstar.ovms.admin.api.vo.EtpInfoSVo;
import com.htstar.ovms.common.core.util.OvmDateUtil;
import com.htstar.ovms.common.core.util.R;
import com.htstar.ovms.common.core.util.WebUtils;
import com.htstar.ovms.common.security.util.SecurityUtils;
import com.htstar.ovms.enterprise.api.entity.CarInfo;
import com.htstar.ovms.report.api.entity.ReportDriverExpense;
import com.htstar.ovms.report.api.entity.ReportExpense;
import com.htstar.ovms.report.api.req.*;
import com.htstar.ovms.report.api.vo.PersonalReportReqVO;
import com.htstar.ovms.report.mapper.ReportExpenseMapper;
import com.htstar.ovms.report.mapper.UseCarReportMapper;
import com.htstar.ovms.report.service.ReportExpenseService;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static cn.hutool.core.util.NumberUtil.roundStr;

/**
 * 费用报表数据
 *
 * @author lw
 * @date 2020-07-27 15:19:34
 */
@Service
@Slf4j
public class ReportExpenseServiceImpl extends ServiceImpl<ReportExpenseMapper, ReportExpense> implements ReportExpenseService {
    @Autowired
    private EtpInfoFeign etpInfoFeign;

    @Autowired
    UseCarReportMapper useCarReportMapper;

    /**
     * 月份统计费用总计费用
     *
     * @param req
     * @return
     */
    @Override
    public R<ReportExpense> getTotalCostByMonth(CostMonthReq req) {
        CostMonthReq req1 = getReq(req);
        ReportExpense reportExpense = baseMapper.getTotalCostByMonth(req1);
        return R.ok(reportExpense);
    }

    /**
     * 按月统计列表
     *
     * @param req
     * @return
     */
    @Override
    public R<List<ReportExpense>> getCostTableByMonth(CostMonthReq req) {
        //年份字段转换
        if (req.getYearDate() != null && !"".equals(req.getYearDate())) {
            req.setYear(req.getYearDate());
        }
        CostMonthReq req1 = getReq(req);
        if (req.getExportStatus() == 1) {
            return this.exportCostTableByMont(req1);
        }
        List<ReportExpense> list = baseMapper.getCostTableByMonth(req1);
        return R.ok(list);
    }

    /**
     * 按车辆统计费用  当月总费用
     *
     * @param req
     * @return
     */
    @Override
    public R<ReportExpense> getTotalCostByCar(CarReportReq req) {
        String monthShort = this.getMonthShort(req);
        Integer etpId = SecurityUtils.getUser().getEtpId();
        //根据本级企业查询本级和下级企业
        if (Objects.equals(req.getEtpId(), null)) req.setEtpId(etpId);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(req.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            req.setEtpIds(etpInfoSVo.getIds());
        });
        //        //有车牌号
        if (req.getLicCode() != null && !"".equals(req.getLicCode())) {
            ByCarReportPageReq carQuer = new ByCarReportPageReq();
            carQuer.setEtpIds(req.getEtpIds());
            carQuer.setLicCode(req.getLicCode());
            List<CarInfo> carInfos = useCarReportMapper.exsitCar(carQuer);
            if (carInfos == null || carInfos.size() == 0) {
                ReportExpense zeroRs = new ReportExpense();
                zeroRs.setApplyCarCount(0);
                zeroRs.setEtcCost(0);
                zeroRs.setFuelCost(0);
                zeroRs.setInsCost(0);
                zeroRs.setMaiCost(0);
                zeroRs.setMotCost(0);
                zeroRs.setOtherCost(0);
                zeroRs.setRepairCost(0);
                zeroRs.setStopCost(0);
                zeroRs.setSuppliesCost(0);
                zeroRs.setTicketCost(0);
                zeroRs.setWashCost(0);
                R.ok(zeroRs);
            }
            List<Integer> carIds = new ArrayList<>();
            for (CarInfo carInfo : carInfos) {
                carIds.add(carInfo.getId());
            }
            req.setCarIds(carIds);
        }

        ReportExpense reportExpense = baseMapper.getTotalCostByCar(req.getEtpIds(), req.getStaTime(), req.getEndTime(), req.getCarIds());
        return R.ok(reportExpense);
    }

    /**
     * 按车辆统计费用列表
     *
     * @param req
     * @return
     */
    @Override
    public R<IPage<ReportExpense>> getCostPageByCar(CarReportReq req) {
        Integer etpId = SecurityUtils.getUser().getEtpId();
        //根据本级企业查询本级和下级企业
        if (Objects.equals(req.getEtpId(), null)) req.setEtpId(etpId);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(req.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            req.setEtpIds(etpInfoSVo.getIds());
        });
        //时间
        String monthShort = this.getMonthShort(req);
        req.setMonthShort(monthShort);
        if (req.getExportStatus() == 1) {
            return this.exportCostByCar(req);
        }
        IPage<ReportExpense> costTableByCar = baseMapper.getCostPageByCar(req);
        return R.ok(costTableByCar);
    }

    /**
     * 查询年月份处理
     *
     * @param req
     * @return
     */
    @Override
    public String getMonthShort(CarReportReq req) {
        String year = req.getYear();
        String month = req.getMonth();
        //年份
        if (StrUtil.isEmpty(year)) {
            LocalDateTime cstNow = OvmDateUtil.getCstNow();
            year = cstNow.format(DateTimeFormatter.ofPattern("yyyy"));
        }
        if (StrUtil.isEmpty(month)) {
            LocalDateTime cstNow = OvmDateUtil.getCstNow();
            //获得月的部分
            month = cstNow.format(DateTimeFormatter.ofPattern("MM"));
        }
        String monthShort = year + "-" + month;
        return monthShort;
    }

    /**
     * 导出
     *
     * @param rows
     * @param fileName
     */
    @Override
    public void exportUtil(List<Map<String, Object>> rows, String fileName) {
        HttpServletResponse response = WebUtils.getResponse();
        // 通过工具类创建writer，默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();
        // 一次性写出内容，使用默认样式，强制输出标题
        //writer.merge(rows.size() - 1, fileName);
        writer.write(rows, true);
        //out为OutputStream，需要写出到的目标流

        //response为HttpServletResponse对象

        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        ServletOutputStream out = null;
        try {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="
                    .concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
            out = response.getOutputStream();
        } catch (Exception e) {
            log.error("{}导出Excel异常", fileName);
        }
        writer.flush(out, true);
        // 关闭writer，释放内存
        writer.close();
        //此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

    private CostMonthReq getReq(CostMonthReq req) {
        String year = req.getYear();
        if (year == null) {
            LocalDateTime cstNow = OvmDateUtil.getCstNow();
            //获得当前时间年的部分
            year = cstNow.format(DateTimeFormatter.ofPattern("yyyy"));
            req.setYear(year);
        }
        Integer etpId = SecurityUtils.getUser().getEtpId();
        //获取后代企业ids
        if (req.getEtpId() == null) {
            req.setEtpId(etpId);
        }
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(req.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            req.setEtpIds(etpInfoSVo.getIds());
        });
        return req;
    }

    private R<List<ReportExpense>> exportCostTableByMont(CostMonthReq req) {
        //导出数据集合
        List<Map<String, Object>> rows = new ArrayList<>();
        List<ReportExpense> list = baseMapper.getCostTableByMonth(req);

        if (CollUtil.isNotEmpty(list)) {
            for (ReportExpense reportExpense : list) {
                LinkedHashMap<String, Object> map = new LinkedHashMap<>();
                map.put("月份", reportExpense.getMonthValue());
                map.put("加油费", roundStr(((double) (reportExpense.getFuelCost()) / 100), 2));
                map.put("通行费", roundStr(((double) (reportExpense.getEtcCost()) / 100), 2));
                map.put("停车费", roundStr(((double) (reportExpense.getStopCost()) / 100), 2));
                map.put("洗车美容费", roundStr(((double) (reportExpense.getWashCost()) / 100), 2));
                map.put("罚单费", roundStr(((double) (reportExpense.getTicketCost()) / 100), 2));
                map.put("汽车用品费", roundStr(((double) (reportExpense.getSuppliesCost()) / 100), 2));
                map.put("保养费", roundStr(((double) (reportExpense.getMaiCost()) / 100), 2));
                map.put("保险费", roundStr(((double) (reportExpense.getInsCost()) / 100), 2));
                map.put("年检费", roundStr(((double) (reportExpense.getMotCost()) / 100), 2));
                map.put("维修费", roundStr(((double) (reportExpense.getRepairCost()) / 100), 2));
                map.put("其他费用", roundStr(((double) (reportExpense.getOtherCost()) / 100), 2));
                rows.add(map);
            }
        }
        this.exportUtil(rows, "按月统计费用");
        return R.ok();
    }

    /**
     * 按车辆统计费用
     *
     * @param req
     * @return
     */
    private R exportCostByCar(CarReportReq req) {
        //导出数据集合
        List<Map<String, Object>> rows = new ArrayList<>();
        req.setSize(Long.MAX_VALUE);
        IPage<ReportExpense> costTableByCar = baseMapper.getCostPageByCar(req);
        List<ReportExpense> records = costTableByCar.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            for (ReportExpense reportExpense : records) {
                LinkedHashMap<String, Object> map = new LinkedHashMap<>();
                map.put("企业", reportExpense.getEtpName());
                map.put("车牌号", reportExpense.getLicCode());
                map.put("加油费", roundStr(((double) (reportExpense.getFuelCost()) / 100), 2));
                map.put("通行费", roundStr(((double) (reportExpense.getEtcCost()) / 100), 2));
                map.put("停车费", roundStr(((double) (reportExpense.getStopCost()) / 100), 2));
                map.put("洗车美容费", roundStr(((double) (reportExpense.getWashCost()) / 100), 2));
                map.put("罚单费", roundStr(((double) (reportExpense.getTicketCost()) / 100), 2));
                map.put("汽车用品费", roundStr(((double) (reportExpense.getSuppliesCost()) / 100), 2));
                map.put("保养费", roundStr(((double) (reportExpense.getMaiCost()) / 100), 2));
                map.put("保险费", roundStr(((double) (reportExpense.getInsCost()) / 100), 2));
                map.put("年检费", roundStr(((double) (reportExpense.getMotCost()) / 100), 2));
                map.put("维修费", roundStr(((double) (reportExpense.getRepairCost()) / 100), 2));
                map.put("其他费用", roundStr(((double) (reportExpense.getOtherCost()) / 100), 2));
                rows.add(map);
            }
        }
        this.exportUtil(rows, "按车辆统计费用");
        return R.ok();
    }

    @Override
    public R<IPage<PersonalReportReqVO>> carTableByPerson(CarReportReq req) {
        if ("".equals(req.getCarUserId())) {
            req.setCarUserId(null);
        }
        Integer etpId = SecurityUtils.getUser().getEtpId();
        //根据本级企业查询本级和下级企业
        if (Objects.equals(req.getEtpId(), null)) req.setEtpId(etpId);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(req.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            req.setEtpIds(etpInfoSVo.getIds());
        });
        String monthShort = this.getMonthShort(req);
        req.setMonthShort(monthShort);
        if (req.getExportStatus() == 1) {
            return this.carReportExportByPerson(req);
        }
        IPage<PersonalReportReqVO> rs = baseMapper.carTableByPerson(req);
        return R.ok(rs);
    }

    @Override
    public R<ReportExpense> carTotalByPerson(CarReportReq req) {
        String monthShort = this.getMonthShort(req);
        Integer etpId = SecurityUtils.getUser().getEtpId();
        //根据本级企业查询本级和下级企业
        if (Objects.equals(req.getEtpId(), null)) req.setEtpId(etpId);
        List<EtpInfoSVo> currentAndParents1 = etpInfoFeign.getCurrentAndParents1(req.getEtpId());
        currentAndParents1.forEach(etpInfoSVo -> {
            req.setEtpIds(etpInfoSVo.getIds());
        });
        ReportExpense reportExpense = baseMapper.getTotalCostByPerson(req.getEtpIds(), req.getStaTime(), req.getEndTime());

        return R.ok(reportExpense);
    }

//    private R<IPage<PersonalReportReqVO>> exportCostTableByPerson(CarReportReq req) {
//        //导出数据集合
//        List<Map<String, Object>> rows = new ArrayList<>();
//        CarReportReqNoPage carReportReqNoPage = new CarReportReqNoPage();
//        BeanUtil.copyProperties(req, carReportReqNoPage);
//        List<PersonalReportReqVO> list = baseMapper.carTableByPersonNoPage(carReportReqNoPage);
//        if (CollUtil.isNotEmpty(list)) {
//            for (PersonalReportReqVO reportExpense : list) {
//                LinkedHashMap<String, Object> map = new LinkedHashMap<>();
//                map.put("人员", reportExpense.get());
//                map.put("加油费", roundStr(((double) (reportExpense.getFuelCost()) / 100), 2));
//                map.put("通行费", roundStr(((double) (reportExpense.getEtcCost()) / 100), 2));
//                map.put("停车费", roundStr(((double) (reportExpense.getStopCost()) / 100), 2));
//                map.put("洗车美容费", roundStr(((double) (reportExpense.getWashCost()) / 100), 2));
//                map.put("罚单费", roundStr(((double) (reportExpense.getTicketCost()) / 100), 2));
//                map.put("其他费用", roundStr(((double) (reportExpense.getOtherCost()) / 100), 2));
//                rows.add(map);
//            }
//        }
//        this.exportUtil(rows, "按人员统计费用");
//        return R.ok();
//    }

    private R<IPage<PersonalReportReqVO>> carReportExportByPerson(CarReportReq req) {
        req.setSize(Long.MAX_VALUE);
        HttpServletResponse response = WebUtils.getResponse();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        writer.renameSheet("报表信息");

        CarReportReqNoPage carReportReqNoPage = new CarReportReqNoPage();
        BeanUtil.copyProperties(req, carReportReqNoPage);
        IPage<PersonalReportReqVO> personalReportReqVOIPage = baseMapper.carTableByPerson(req);
        List<PersonalReportReqVO> list = personalReportReqVOIPage.getRecords();
        if (list == null || list.isEmpty()) {
            return R.ok();
        }

//        List<Map<String, Object>> totalrows = new ArrayList<>();
//        Map<String, Object> row1 = new LinkedHashMap<>();
//        double costTotal = 0;
//        int useTotal = 0;
//        for (PersonalReportReqVO one : list) {
//            costTotal += Double.parseDouble(one.getCostCount());
//            useTotal += Integer.parseInt(one.getUseCount());
//        }
//
//        row1.put("出车次数总计", useTotal + "");
//        row1.put("费用总计（元）", costTotal + "");
//        totalrows.add(row1);
//        writer.write(totalrows, true);
        List<Map<String, Object>> rows = new ArrayList<>();
        for (PersonalReportReqVO reportExpense : list) {
            LinkedHashMap<String, Object> map = new LinkedHashMap<>();
            map.put("企业", reportExpense.getEtpName());
            map.put("人员", reportExpense.getName());
            map.put("加油费", roundStr(((double) (reportExpense.getFuelCost()) / 100), 2));
            map.put("通行费", roundStr(((double) (reportExpense.getEtcCost()) / 100), 2));
            map.put("停车费", roundStr(((double) (reportExpense.getStopCost()) / 100), 2));
            map.put("洗车美容费", roundStr(((double) (reportExpense.getWashCost()) / 100), 2));
            map.put("罚单费", roundStr(((double) (reportExpense.getTicketCost()) / 100), 2));
            map.put("其他费用", roundStr(((double) (reportExpense.getOtherCost()) / 100), 2));
            rows.add(map);
        }
        writer.write(rows, true);
        OutputStream out = null;
        try {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(URLEncoder.encode(
                    "用车报表-按人统计" + OvmDateUtil.getCstNowDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
                    , "UTF-8").getBytes("UTF-8"), "ISO8859-1") + ".xlsx");
            out = response.getOutputStream();
            writer.flush(out, true);
        } catch (
                IOException e) {
            log.error("用车报表-按人统计", e);
        } finally {
            writer.close();
            IoUtil.close(out);
            return null;
        }
    }
}
